# -*- coding:utf-8 -*-
"""Created By Corvo"""

from mod.common.minecraftEnum import ActorDamageCause
from ....server.system.base import *

"""
模块实体基类
- 构造后的生物类需要注册到 <MobModuleServer> 方可生效
- 目前采用集中管理触发回调，减少大量实体监听事件的压力
- 构造自定义模组玩家和生物的基类，可通过继承 <ModuleEntityMgr> 

- 目前版本并没有伤害类型过滤，需要手动处理
"""


class ModuleEntityMgr(ServerBaseSystem):
    """
    模块实体管理\n
    - 提供常用触发接口
    """
    __mVersion__ = 3

    def OnHitRecall(self, hit_list):
        # type: (list) -> None
        """碰撞回调"""

    # -----------------------------------------------------------------------------------

    """造成伤害"""

    def OnDealDamage(self, args):
        # type: (dict) -> None
        """
        实体造成伤害时触发\n
        - srcId: str 伤害源id
        - projectileId: str 投射物id
        - entityId: str 被伤害id
        - damage: int 伤害值，允许修改，设置为0则此次造成的伤害为0
        - absorption: int 伤害吸收生命值，详见AttrType枚举的ABSORPTION
        - cause: str 伤害来源，详见Minecraft枚举值文档的ActorDamageCause
        - knock: bool 是否击退被攻击者，允许修改，设置该值为False则不产生击退
        - ignite: bool 是否点燃被伤害者，允许修改，设置该值为True产生点燃效果，反之亦然
        """

    def OnActuallyDealDamage(self, args):
        # type: (dict) -> None
        """
        实体实际造成伤害\n
        实体实际受到伤害时触发，相比于DamageEvent，该伤害为经过护甲及buff计算后，实际的扣血量\n
        - srcId: str 伤害源id
        - projectileId: str 投射物id
        - entityId: str 被伤害id
        - damage: int 伤害值，允许修改，设置为0则此次造成的伤害为0
        - cause: str 伤害来源，详见Minecraft枚举值文档的ActorDamageCause
        """

    def OnKillEntity(self, victimId):
        # type: (str) -> None
        """
        实体杀死其他实体触发\n
        - victimId: str
        """

    """承受伤害"""

    def OnTookDamage(self, args):
        # type: (dict) -> None
        """
        实体受到伤害时触发\n
        - srcId: str 伤害源id
        - projectileId: str 投射物id
        - entityId: str 被伤害id
        - damage: int 伤害值，允许修改，设置为0则此次造成的伤害为0
        - absorption: int 伤害吸收生命值，详见AttrType枚举的ABSORPTION
        - cause: str 伤害来源，详见Minecraft枚举值文档的ActorDamageCause
        - knock: bool 是否击退被攻击者，允许修改，设置该值为False则不产生击退
        - ignite: bool 是否点燃被伤害者，允许修改，设置该值为True产生点燃效果，反之亦然
        """

    def OnActuallyTookDamage(self, args):
        # type: (dict) -> None
        """
        实体实际承受伤害\n
        实体实际受到伤害时触发，相比于DamageEvent，该伤害为经过护甲及buff计算后，实际的扣血量\n
        - srcId: str 伤害源id
        - projectileId: str 投射物id
        - entityId: str 被伤害id
        - damage: int 伤害值，允许修改，设置为0则此次造成的伤害为0
        - cause: str 伤害来源，详见Minecraft枚举值文档的ActorDamageCause
        """

    """交互相关"""

    def OnTriggerEvent(self, event_name):
        # type: (str) -> None
        """实体触发生物事件"""

    def OnInteractedByPlayer(self, player_id, item_dict):
        # type: (str, dict) -> None
        """
        玩家与有minecraft:interact组件的生物交互时触发该事件\n
        例如玩家手持空桶对牛挤奶、玩家手持打火石点燃苦力怕
        """

    """生命相关"""

    def OnFinalDelHealth(self, value):
        # type: (int) -> None
        """最终减少生命"""

    def OnFinalAddHealth(self, value):
        # type: (int) -> None
        """最终增加生命"""

    """死亡相关"""

    def OnWillDie(self, args):
        # type: (dict) -> None
        """
        实体将要死亡事件\n
        可用于死亡前无敌然后播放动画特效等\n
        ----\n        - srcId: str 伤害源id
        - projectileId: str 投射物id
        - entityId: str 被伤害id
        - damage: int 伤害值，允许修改，设置为0则此次造成的伤害为0
        - cause: str 伤害来源，详见Minecraft枚举值文档的ActorDamageCause
        """

    def OnDeath(self, killer):
        # type: (str) -> None
        """
        实体死亡事件\n
        - killer: str 击杀者Id
        """


class ModuleEntityPreset(ModuleEntityMgr, LivingEntity):
    """模块实体预设"""
    __mVersion__ = 2

    def __init__(self, entityId):
        ModuleEntityMgr.__init__(self, MDKConfig.GetModuleServer())
        LivingEntity.__init__(self, entityId)

    def OnDestroy(self):
        ModuleEntityMgr.OnDestroy(self)

    _mob_module = None

    @property
    def MobModule(self):
        # type: () -> MDKConfig.GetPresetModule().MobModuleServer
        if ModuleEntityPreset._mob_module:
            return ModuleEntityPreset._mob_module
        module = self.ModuleSystem.GetModule(MDKConfig.GetPresetModule().MobModuleServer.GetId())
        if not module:
            return None
        ModuleEntityPreset._mob_module = weakref.proxy(module)
        return ModuleEntityPreset._mob_module

    def RegisterHitRecall(self):
        """注册碰撞回调"""
        if not self.MobModule:
            return
        self.MobModule.RegisterHitDetection(self.id)

    def UnRegisterHitRecall(self):
        """反注册碰撞回调"""
        if not self.MobModule:
            return
        self.MobModule.UnRegisterHitDetection(self.id)


class EntityServerPresetSkillBase(ModuleEntityPreset):
    """
    预设技能实体生物实体类\n
    用于处理完全由variant控制的技能生物\n

    - 来源：《电锯人》模组的魔物实体基类
    """
    __mVersion__ = 3

    def __init__(self, entityId):
        super(EntityServerPresetSkillBase, self).__init__(entityId)

        config = self.GetConfig()
        if not config:
            print "[error]", "该生物类型尚未配置:", self.type_str
            return

        attributes = config.get("attributes", {})
        self.health = attributes.get(GameAttr.Health, 1)  # 生命
        self.attack = attributes.get(GameAttr.Attack, 1)  # 攻击
        attr = config.get(GameAttr.Attack, {"damage": 1, "cd": 1})

        self.attack_cd = int(attr["cd"] * 30)

        attr = config.get("sk1", {"damage": 1, "cd": 1})
        self.sk1_damage, self.sk1_cd = attr.get("damage", self.attack), int(attr["cd"] * 30)
        attr = config.get("sk2", {"damage": 1, "cd": 1})
        self.sk2_damage, self.sk2_cd = attr.get("damage", self.attack), int(attr["cd"] * 30)
        attr = config.get("sk3", {"damage": 1, "cd": 1})
        self.sk3_damage, self.sk3_cd = attr.get("damage", self.attack), int(attr["cd"] * 30)

        self.InitHealth(self.health)
        self.SetAttack(self.attack)

        self._trigger_map = self.ConfigTriggerMap()
        self._cd_counter = {}

        self.TriggerResetSkill()

        self.update_timer = self.game_comp.AddRepeatedTimer(1, self.OnUpdateSecond)

    # -----------------------------------------------------------------------------------

    def ConfigTriggerMap(self):
        """配置事件回调"""
        return {
            "event:active_delayed_attack": self.TriggerAttack,
            "event:active_attack": self.ActiveAttack,
            "event:active_skill1": self.ActiveSkill1,
            "event:active_skill2": self.ActiveSkill2,
            "event:active_skill3": self.ActiveSkill3,
            "event:reset_skill": self.ResetSkill,
            "event:active_death": self.ActiveDeath
        }

    def GetConfig(self):
        # type: () -> dict
        """获得生物配置"""
        return {
            GameEntity.zombie: {
                "attack": {"damage": 1, "cd": 1},
                "sk1": {"damage": 1, "cd": 1},
                "sk2": {"damage": 1, "cd": 1},
                "sk3": {"damage": 1, "cd": 1},
            }
        }

    # -----------------------------------------------------------------------------------

    def ConfigEvent(self):
        super(EntityServerPresetSkillBase, self).ConfigEvent()
        self.defaultEvent.update({
            ServerEvent.OnScriptTickServer: self.OnScriptTickServer,
        })

    def OnDestroy(self):
        self.game_comp.CancelTimer(self.update_timer)
        del self.update_timer
        del self._trigger_map
        super(EntityServerPresetSkillBase, self).OnDestroy()

    # -----------------------------------------------------------------------------------

    def IsSkillOnCd(self, skill_key):
        # type: (str) -> bool
        """技能是否在冷却"""
        return skill_key in self._cd_counter

    # -----------------------------------------------------------------------------------

    def TriggerAttack(self):
        """
        激活攻击行为\n
        - 用于普攻或技能的触发
        """
        if not self.IsSkillOnCd("sk1"):
            self.TriggerCustomEvent("event:active_skill1")
        elif not self.IsSkillOnCd("sk2"):
            self.TriggerCustomEvent("event:active_skill2")
        elif not self.IsSkillOnCd("sk3"):
            self.TriggerCustomEvent("event:active_skill3")
        elif not self.IsSkillOnCd("attack"):
            self.TriggerCustomEvent("event:active_attack")

    def ActiveAttack(self):
        """激活攻击"""
        self._cd_counter["attack"] = self.attack_cd

    def ActiveSkill1(self):
        """激活技能1"""
        self._cd_counter["sk1"] = self.sk1_cd

    def ActiveSkill2(self):
        """激活技能2"""
        self._cd_counter["sk2"] = self.sk2_cd

    def ActiveSkill3(self):
        """激活技能3"""
        self._cd_counter["sk3"] = self.sk3_cd

    def ResetSkill(self):
        """
        激活重置技能\n
        - 用于生物重新获得可攻击行为
        - 重置生物的技能显示
        """

    def ActiveDeath(self):
        """
        激活死亡\n
        - 主要用于死亡动画
        """

    # -----------------------------------------------------------------------------------

    def TriggerResetSkill(self):
        """重置技能触发"""
        if not self.IsAlive():
            return
        self.TriggerCustomEvent("event:reset_skill")

    def OnTriggerEvent(self, event_name):
        trigger = self._trigger_map.get(event_name)
        if trigger:
            trigger()

    def OnScriptTickServer(self):
        # 技能冷却
        if not self._cd_counter:
            return
        for skill_key, cd in self._cd_counter.items():
            cd -= 1
            if cd <= 0:
                self._cd_counter.pop(skill_key, None)
                continue
            self._cd_counter[skill_key] = cd

    def OnUpdateSecond(self):
        """服务端秒更新"""
